package com.zx.map.controller.timer;

import com.zx.map.dao.model.AgentInfo;
import com.zx.map.dao.model.CustAcctLog;
import com.zx.map.service.*;
import com.zx.map.service.model.*;
import com.zx.map.utils.MyBeanUtils;
import com.zx.map.utils.SUConstants;
import com.zx.mobile.domain.CustAcctLogQueryDomain;
import com.zx.platform.utils.DateUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;

/**
 * 代理商收益汇总服务  定时每天凌晨执行
 *
 * @author Jaelyn
 */
@Component
public class ShareProfitTimerController {
	private static Logger log = Logger
			.getLogger(ShareProfitTimerController.class);

	private final static int PAGEDEFAULTSIZE = 100;
	/**
	 * 普通代理发展的代理  默认分润
	 */
	private BigDecimal defaultRate = new BigDecimal(2 / 10000d);
	/**
	 * 商户流水记录表
	 */
	@Autowired
	private CustAcctLogService custAcctLogService;
	/**
	 * 商户表
	 */
	@Autowired
	private MerchantInfoService merchantInfoService;
	/**
	 * 分享收益表
	 */
	@Autowired
	private ShareProfitLogService shareProfitLogService;
	/**
	 * 代理商表
	 */
	@Autowired
	private AgentInfoService agentInfoService;
	/**
	 * 分享收益详情表
	 */
	@Autowired
	private ShareProfitDetailLogService shareProfitDetailLogService;

	/**
	 * 代理商留扣表
	 */
	@Autowired
	private AgentLeftService agentLeftService;

	/**
	 * add by Jaelyn
	 * 1·分页处理当天的流水记录 ,以商户和商户对应的代理商层级（代理商ID）为维度，统计商户交易对代理商产品的分润 同级别的只计算一级分润
	 * 2.以代理商为维度，统计代理商收益信息
	 * 3.保存代理商收益日志信息，更新总的收益记录
	 */
	public void calculateAgentProfit() {
		try {
			Date currentDate = new Date();
			log.info("分享收益汇总开始时间，" + currentDate);
			//删除当天分润明细数据 方便用户分润数据重跑，防止产生重复数据
			deleteProfitDetailDirtyData(currentDate);

			String yesterday = DateUtils.dateToString(
					DateUtils.addDate(currentDate, -1), "yyyy-MM-dd");
			CustAcctLogQueryDomain custParams = new CustAcctLogQueryDomain();
			custParams.setBeginDate(yesterday);
			custParams.setEndDate(yesterday);
			custParams.setPageSize(PAGEDEFAULTSIZE);
			int custCount = custAcctLogService.getPageSizeByDomain(custParams, null);
			log.info("分享收益获取待处理数据记录：" + custCount);
			if (custCount > 0) {
				int pageTotalNum = (int) Math.ceil(custCount / (double) PAGEDEFAULTSIZE);// 获取总页数 逐页进行数据处理
				log.info("分享收益获取待处理批次：" + pageTotalNum);
				Map<String, ShareProfitDetailLogModel> shareProfitDetailLogModelHashMap = new HashMap<String, ShareProfitDetailLogModel>();
				for (int i = 1; i <= pageTotalNum; i++) {
					log.info("分享收益正在处理第" + i + "批次");
					try {
						custParams.setPageNum(i);
						Map custAcctRecords = custAcctLogService.getPageByDomain(custParams, null);
						List<CustAcctLog> modelList = (List<CustAcctLog>) custAcctRecords.get("list");
						//2、以商户和商户对应的代理商层级（代理商ID）为维度，统计商户交易对代理商产品的分润
						countAgentProfitByMerchant(shareProfitDetailLogModelHashMap, modelList);
					} catch (Exception e) {
						log.error("分享收益 查询交易记录异常", e);  //最好发送短信通知到负责人
					}

				}
				log.info("分享收益保存明细数据");  // 3、将该交易收益汇总  以代理商为维度，统计代理商收益信息
				Map<String, ShareProfitLogModel> shareProfitLogModelHashMap = new HashMap<String, ShareProfitLogModel>();
				calculateTotleAndSaveDetailData(shareProfitDetailLogModelHashMap, shareProfitLogModelHashMap);

				log.info("分享收益保存汇总数据");//将最终数据保存入库  分享收益数据  更新或者新增
				saveAgentTotleProfit(shareProfitLogModelHashMap);
			}
			log.info("分享收益汇总结束时间" + new Date());
		} catch (Exception e) {
			log.error("分享收益汇总异常", e);  //最好发送短信通知到负责人
		}

	}

	/**
	 * 保存或者更新代理商总的收益
	 *
	 * @param shareProfitLogModelHashMap
	 */
	private void saveAgentTotleProfit(Map<String, ShareProfitLogModel> shareProfitLogModelHashMap) {
		double yesterdayTotalShareProfit=0d;
		for (Map.Entry<String, ShareProfitLogModel> entry : shareProfitLogModelHashMap.entrySet()) {
			try {
			ShareProfitLogModel temp = entry.getValue();
			log.error("保存当天总收益,数据："+MyBeanUtils.beanToJson(temp));
			yesterdayTotalShareProfit+=temp.getSprofitAvlAmt();
			ShareProfitLogModel existSpModel = shareProfitLogService.queryProfitByCustId(temp.getCustId());
			if (null != existSpModel) {
				existSpModel.setSprofitAvlAmt(new BigDecimal(temp.getSprofitAvlAmt()).add(new BigDecimal(existSpModel.getSprofitAvlAmt())).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
				existSpModel.setSprofitBal(new BigDecimal(temp.getSprofitBal()).add(new BigDecimal(existSpModel.getSprofitBal())).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
				existSpModel.setCreateDate(new Date());
				existSpModel.setUpdateDate(new Date());
				shareProfitLogService.update(existSpModel);
			} else {
				temp.setCreateDate(new Date());
				temp.setUpdateDate(new Date());
				shareProfitLogService.add(temp);
			}
			}catch (Exception e){
				log.error("保存当天总收益异常,数据："+MyBeanUtils.beanToJson(entry.getValue()),e);
			}
		}
		SaveHistoryDataTimer.yesterdayTotalShareProfit=yesterdayTotalShareProfit;
		log.error("昨日总分润金额："+yesterdayTotalShareProfit);
	}

	/**
	 * 计算代理商一天内总的收益，并保存详情信息
	 *
	 * @param shareProfitDetailLogModelHashMap
	 * @param shareProfitLogModelHashMap
	 */
	private void calculateTotleAndSaveDetailData(Map<String, ShareProfitDetailLogModel> shareProfitDetailLogModelHashMap, Map<String, ShareProfitLogModel> shareProfitLogModelHashMap) {
		for (Map.Entry<String, ShareProfitDetailLogModel> entry : shareProfitDetailLogModelHashMap.entrySet()) {
			try {
				ShareProfitDetailLogModel spDetailModel = entry.getValue();
			BigDecimal tempProfit = new BigDecimal(spDetailModel.getSpDetailAmt().toString()).setScale(2, BigDecimal.ROUND_HALF_UP);
			log.info("初步汇总用户号：" + entry.getKey() + "	用户贡献收益:" + tempProfit);
			if (tempProfit.doubleValue() > 0) {// 保存收益共享不为零的数据
				// 保存到分享收益明细表
				shareProfitDetailLogService.add(spDetailModel);
				String agentId = spDetailModel.getAgentId();
				if (shareProfitLogModelHashMap.containsKey(agentId)) {
					// map中包含数据的 增加数据
					ShareProfitLogModel model = shareProfitLogModelHashMap.get(agentId);
					model.setSprofitAvlAmt(new BigDecimal(model.getSprofitAvlAmt()).add(tempProfit).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
					model.setSprofitBal(new BigDecimal(model.getSprofitBal()).add(tempProfit).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
				} else {
					// 设置代理对应的商户
					ShareProfitLogModel model = new ShareProfitLogModel();
					model.setCustId(spDetailModel.getAgentId());
					model.setCustSysAccount(spDetailModel.getAgentSysAccount());
					model.setSprofitBal(tempProfit.doubleValue());
					model.setSprofitAvlAmt(tempProfit.doubleValue());
					model.setCreateDate(new Date());
					shareProfitLogModelHashMap.put(agentId, model);
				}
			}
			}catch (Exception e){
				log.error("保存明细异常",e);
			}
		}
	}

	private void countAgentProfitByMerchant(Map<String, ShareProfitDetailLogModel> shareProfitDetailLogModelHashMap, List<CustAcctLog> modelList) {
		for (CustAcctLog custAcctLogModel : modelList) {
			//获取商户和代理商信息
			log.debug("交易信息："+MyBeanUtils.beanToJson(custAcctLogModel));
			if (isWhiteTransType(custAcctLogModel)) {
				continue;
			}
			try {
				MerchantInfoModel merchantInfoModel = merchantInfoService.getModelByKey(custAcctLogModel.getCustId());
				AgentInfoModel agentInfoModel = agentInfoService.getModelByKey(merchantInfoModel.getAgentId());
				AgentInfo agentInfo = new AgentInfo();
				BeanUtils.copyProperties(agentInfoModel, agentInfo);
				//分解层级，组装map的key
				String agentBsidStr = agentInfo.getBsid();
				String[] agentIdArrayTmp = agentBsidStr.split("-");
				List<String> agentBsidArray = Arrays.asList(agentIdArrayTmp).subList(1, agentIdArrayTmp.length);//A143是总公司，不参与计算
				int length = agentBsidArray.size(); //代理商层级数量
				//Collections.reverse(agentBsidArray);
				String agentIdTmp = agentInfo.getAgentId();
				String mapKey = merchantInfoModel.getMerchantId() + "-" + agentIdTmp;
				//查询各代理商的分润比例，  大于三级的说明是普通 ,默认万二分润   不合并到 含有连续同等级的场景，为了减少数据库查询
				if (length > 3) {
					calculateProfitByDefaultRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, merchantInfoModel, agentInfo, 0);
				} else if (length > 0) {
					List<AgentInfo> agentInfoArrayList = agentInfoService.queryAgentInfoByIdList(agentBsidArray);
					boolean isCalculateByDefault=checkAgentLevel(length,agentInfoArrayList);

					if(isCalculateByDefault){
						calculateProfitByDefaultRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, merchantInfoModel, agentInfo, 0);
						continue;
					}

					//根据产品和商户信息等 查询分润比例
					String transType = custAcctLogModel.getTransType();
					BigDecimal[] agentProfitRate = agentLeftService.getleftRate(agentInfoArrayList, Long.valueOf(transType));
					for (int j = 0; j < agentInfoArrayList.size(); j++) {
						agentIdTmp = agentBsidArray.get(j);
						mapKey = merchantInfoModel.getMerchantId() + "-" + agentIdTmp;
						calculateProfitByRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, agentProfitRate[j], merchantInfoModel, agentInfoArrayList.get(j), agentInfoArrayList.size() - j);
					}

				} else {//商户属于总公司，不进行分润
				}
			} catch (Exception e) {
			   log.error("分享收益 汇总商户交易异常",e);
			}
		}
	}

	private boolean checkAgentLevel(int bsidLength, List<AgentInfo> agentInfoArrayList) {

		int lengthTmp = agentInfoArrayList.size();//数据不完整，查找为空
		if (bsidLength != lengthTmp) {
			log.error("代理商信息丢失");
			return true;
		}
		bsidLength = lengthTmp;
		if(agentInfoArrayList.get(bsidLength-1).getAgentLevel().equals(SUConstants.AGENT_LEVEL_WILL)){
			return true;
		}
		//检查层级关系   代理层级异常，按普通的计算
		if (bsidLength >=1) {
			if (!agentInfoArrayList.get(0).getAgentLevel().equals(SUConstants.AGENT_LEVEL_SUBCOMPANY)) {
				return true;
			}
		}
		if(bsidLength>=2){
			if (!agentInfoArrayList.get(1).getAgentLevel().equals(SUConstants.AGENT_LEVEL_SUPER)) {
				return true;
			}
		}
		if(bsidLength==3){
			if (!agentInfoArrayList.get(2).getAgentLevel().equals(SUConstants.AGENT_LEVEL_COMMON)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 超出三级的代理商的交易  分润计算
	 *
	 * @param shareProfitDetailLogModelHashMap
	 * @param mapKey
	 * @param custAcctLogModel
	 * @param merchantInfoModel
	 * @param agentInfo
	 * @param i
	 */
	private void calculateProfitByDefaultRate(Map<String, ShareProfitDetailLogModel> shareProfitDetailLogModelHashMap, String mapKey, CustAcctLog custAcctLogModel, MerchantInfoModel merchantInfoModel, AgentInfo agentInfo, int i) {
		String transType = custAcctLogModel.getTransType();
		if (transType.equals(SUConstants.TRANSTYPE_INCOME)) {  //线上扫码收款
			calculateProfitByRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, defaultRate, merchantInfoModel, agentInfo, i);
		} else if (transType.equals(SUConstants.TRANSTYPE_OFFLINE_INCOME)) {
			calculateProfitByRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, defaultRate, merchantInfoModel, agentInfo, i);
		}else if (transType.equals(SUConstants.TRANSTYPE_NOCARDINCOME)) {
			calculateProfitByRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, defaultRate, merchantInfoModel, agentInfo, i);
		} else if (transType.equals(SUConstants.TRANSTYPE_CARDINCOME)) {
			calculateProfitByRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, defaultRate, merchantInfoModel, agentInfo, i);
		} else if (transType.equals(SUConstants.TRANSTYPE_CREDITENCASH)) {
			//calculateProfitByRate(shareProfitDetailLogModelHashMap,mapKey,custAcctLogModel,defaultRate,merchantInfoModel,agentInfo,1);
		} else if (transType.equals(SUConstants.TRANSTYPE_T0ENCASH)) {
			//calculateProfitByRate(shareProfitDetailLogModelHashMap,mapKey,custAcctLogModel,defaultRate,merchantInfoModel,agentInfo,1);
		} else if (transType.equals(SUConstants.TRANSTYPE_INSURANCE)) {
			calculateProfitByRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, new BigDecimal(5 / 1000d), merchantInfoModel, agentInfo, i);
		} else if (transType.equals(SUConstants.TRANSTYPE_CONSUME)) {
			calculateProfitByRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, new BigDecimal(5 / 1000d), merchantInfoModel, agentInfo, i);
		}else if (transType.equals(SUConstants.TRANSTYPE_RECHARGE)) {
			calculateProfitByRate(shareProfitDetailLogModelHashMap, mapKey, custAcctLogModel, defaultRate, merchantInfoModel, agentInfo, i);
		}
	}

	/**
	 * 不参加分润的交易
	 *
	 * @param custAcctLogModel
	 * @return
	 */
	private boolean isWhiteTransType(CustAcctLog custAcctLogModel) {
		String transType = custAcctLogModel.getTransType();
		if (SUConstants.TRANSTYPE_INCOME.equals(transType) ||
				SUConstants.TRANSTYPE_OFFLINE_INCOME.equals(transType) ||
				SUConstants.TRANSTYPE_NOCARDINCOME.equals(transType) ||
				SUConstants.TRANSTYPE_T0ENCASH.equals(transType) ||
				SUConstants.TRANSTYPE_CARDINCOME.equals(transType) ||
				SUConstants.TRANSTYPE_INSURANCE.equals(transType) ||
				SUConstants.TRANSTYPE_CREDITENCASH.equals(transType) ||
				SUConstants.TRANSTYPE_CONSUME.equals(transType) ||
				SUConstants.TRANSTYPE_RECHARGE.equals(transType)) {
			return false;
		} else {
			return true;
		}

	}

	/**
	 * 删除脏数据
	 *
	 * @param currentDate
	 */
	private void deleteProfitDetailDirtyData(Date currentDate) {
		String today = DateUtils.dateToString(currentDate, "yyyyMMdd");
		ShareProfitDetailLogModel delParams = new ShareProfitDetailLogModel();
		delParams.setSpDetailDay(today);
		shareProfitDetailLogService.delete(delParams);
	}

	/**
	 * 根据分润比率 计算代理商所得效益，并转化为收益详情数据对象
	 *
	 * @param shareProfitDetailLogModelHashMap
	 * @param mapKey
	 * @param custAcctLogModel
	 * @param agentProfitRate
	 * @param merchantInfoModel
	 * @param agentInfo
	 * @param profitType
	 */
	private void calculateProfitByRate(Map<String, ShareProfitDetailLogModel> shareProfitDetailLogModelHashMap, String mapKey, CustAcctLog custAcctLogModel, BigDecimal agentProfitRate, MerchantInfoModel merchantInfoModel, AgentInfo agentInfo, long profitType) {
		if (shareProfitDetailLogModelHashMap.containsKey(mapKey)) {
			ShareProfitDetailLogModel shareProfitDetailLogModel = shareProfitDetailLogModelHashMap.get(mapKey);
			BigDecimal profitAdd = agentProfitRate.multiply(new BigDecimal(custAcctLogModel.getOriginalAmt()));
			BigDecimal profit = new BigDecimal(shareProfitDetailLogModel.getSpDetailAmt()).add(profitAdd);
			shareProfitDetailLogModel.setSpDetailAmt(profit.doubleValue());
			shareProfitDetailLogModelHashMap.put(mapKey, shareProfitDetailLogModel);// 将最新数值保存
		} else {
			//获取代理商信息
			ShareProfitDetailLogModel spDetail = transformToSpDetail(merchantInfoModel, agentInfo, profitType);
			BigDecimal profit = agentProfitRate.multiply(new BigDecimal(custAcctLogModel.getOriginalAmt()));
			spDetail.setSpDetailAmt(profit.doubleValue());
			shareProfitDetailLogModelHashMap.put(mapKey, spDetail);//设置直接分润信息
		}
	}


	/**
	 * 转换为 分享收益明细表
	 *
	 * @param temp
	 * @param agent
	 * @param profitType
	 */
	private ShareProfitDetailLogModel transformToSpDetail(MerchantInfoModel temp, AgentInfo agent, long profitType) {
		ShareProfitDetailLogModel addSpDetail = new ShareProfitDetailLogModel();
		addSpDetail.setAgentId(agent.getAgentId());
		addSpDetail.setAgentSysAccount(agent.getSysAccount());
		addSpDetail.setCreateDate(new Date());
		addSpDetail.setMerchantId(temp.getMerchantId());
		addSpDetail.setMerchantName(temp.getMerchantName());
		addSpDetail.setMerSysAccount(temp.getSysAccount());
		addSpDetail.setSpDetailType(profitType + "");  //收益类型
		addSpDetail.setSpDetailDay(DateUtils.dateToString(new Date(), "yyyyMMdd"));
		addSpDetail.setRemark("");
		addSpDetail.setAgentLevel(agent.getAgentLevel());//保存代理商等级方便计算分润
		return addSpDetail;
	}

}
